// steps 1,4 - http://en.wikipedia.org/wiki/Bzip2#Compression_stack

#include <iostream>
#include <fstream>
using namespace std;

#include "RLE.h"

bool equals(unsigned int bytes, const unsigned char *buf1, const unsigned char *buf2);

#if 1	// RLE_AB

int main()
{
	const int BUFLEN = 1024;	// 1kiB
	unsigned char buffer[BUFLEN];
	ifstream fin("txt_ab.txt", ios_base::in | ios_base::binary);
	if(!fin.is_open()) { cerr << "error" << endl; return 0; }
	ofstream fout("txt_ab.rle", ios_base::out | ios_base::binary);
	if(!fout.is_open()) { cerr << "error" << endl; return 0; }
	//
	streamsize read;
	unsigned int enc_len, dec_len;
	unsigned short encoded[BUFLEN];
	unsigned char decoded[BUFLEN];
	while(1)
	{
		fin.read((char *)buffer, BUFLEN);
		if((read = fin.gcount()) > 0)
		{
			RLE::Encode_AB(buffer, read, encoded, enc_len);
			fout.write((char *)encoded, sizeof(short)*enc_len);
			RLE::Decode_AB(encoded, enc_len, decoded, dec_len);
			if((read == dec_len) && equals(read, buffer, decoded))
				cout << "Ok" << endl;
			else
				cout << "Err" << endl;
		}
		if(fin.eof()) break;
	}
	//
	fout.close();
	fin.close();
	return 0;
}

#else	// RLE_MN5

int main()
{
	const int BUFLEN = 1024;	// 1kiB
	unsigned char buffer[BUFLEN];
	ifstream fin("txt_mn5.txt", ios_base::in | ios_base::binary);
	if(!fin.is_open()) { cerr << "error" << endl; return 0; }
	ofstream fout("txt_mn5.rle", ios_base::out | ios_base::binary);
	if(!fout.is_open()) { cerr << "error" << endl; return 0; }
	// RLE (MN5 variation of length 4) encoding
	//  - example: "AAAAAAABBBBCCCD" -->  "AAAA\3BBBB\0CCCD"
	streamsize read;
	unsigned int enc_len, dec_len;
	unsigned char encoded[BUFLEN], decoded[BUFLEN];
	while(1)
	{
		fin.read((char *)buffer, BUFLEN);
		if((read = fin.gcount()) > 0)
		{
			RLE::Encode_MN5(buffer, read, encoded, enc_len);
			fout.write((char *)encoded, enc_len);
			RLE::Decode_MN5(encoded, enc_len, decoded, dec_len);
			if((read == dec_len) && equals(read, buffer, decoded))
				cout << "Ok" << endl;
			else
				cout << "Err" << endl;
		}
		if(fin.eof()) break;
	}
	//
	fout.close();
	fin.close();
	return 0;
}

#endif


bool equals(unsigned int bytes, const unsigned char *buf1, const unsigned char *buf2)
{
	for(unsigned int i = 0; i < bytes; i++)
		if(buf1[i] != buf2[i])
			return false;
	return true;
}